#ifndef MYAMG_DATACONVERT_CUH
#define MYAMG_DATACONVERT_CUH
#include <FileIO.h>
#include <../yhamg.h>
#include <../Data/CSRMatrix.cuh>

namespace myamg {
    inline auto CSR2YHAMGCsrMatrix(const std::string& fileName) {
        CsrMatrixReader<int, double> reader(fileName);
        auto rowPtr = new int[reader.getIndexPoints().size()];
        auto colInd = new int[reader.getIndices().size()];
        auto values = new double[reader.getData().size()];
        std::copy(reader.getIndexPoints().begin(),reader.getIndexPoints().end(), rowPtr);
        std::copy(reader.getIndices().begin(),reader.getIndices().end(), colInd);
        std::copy(reader.getData().begin(),reader.getData().end(), values);
        auto numRows = reader.getNDim();
        return std::make_unique<YHAMG::CSRMatrix>(numRows, numRows, rowPtr, colInd, values, 0);
    }

    inline auto CSRRhs2YHAMGVector(const std::string& fileName) {
        CsrMatrixReader<int, double> reader(fileName);
        auto rhs = new double[reader.getRhs().size()];
        std::copy(reader.getRhs().begin(),reader.getRhs().end(), rhs);
        auto numRows = reader.getNDim();
        return std::make_unique<YHAMG::Vector>(numRows, rhs, 0);
    }

    inline auto CSRX2YHAMGVector(const std::string& fileName) {
        CsrMatrixReader<int, double> reader(fileName);
        auto x = new double[reader.getX().size()];
        std::copy(reader.getX().begin(),reader.getX().end(), x);
        auto numRows = reader.getNDim();
        return std::make_unique<YHAMG::Vector>(numRows, x, 0);
    }

    template<typename Integer, typename Real, typename Allocator = MatrixHostAllocator>
    auto CSR2Matrix(const std::string& filename) {
        CsrMatrixReader<Integer, Real> reader(filename);
        CSRMatrix<Integer, Real, Allocator> myCSRMatrix(reader.getNDim(), reader.getNDim(), reader.getNData());
        myCSRMatrix.setRowPtr(reader.getIndexPoints());
        myCSRMatrix.setColIndex(reader.getIndices());
        myCSRMatrix.setValues(reader.getData());
        return std::move(myCSRMatrix);
    }

    template<typename Real, typename Allocator = MatrixHostAllocator>
    auto CSRRhs2Vector(const std::string& filename) {
        CsrMatrixReader<int, Real> reader(filename);
        Vector<Real, Allocator> myVector(reader.getNDim());
        myVector.setValues(reader.getRhs());
        return std::move(myVector);
    }

    template<typename Real, typename Allocator = MatrixHostAllocator>
    auto CSRX2Vector(const std::string& filename) {
        CsrMatrixReader<int, Real> reader(filename);
        Vector<Real, Allocator> myVector(reader.getNDim());
        myVector.setValues(reader.getX());
        return std::move(myVector);
    }

    template<typename Allocator = MatrixHostAllocator>
    auto YHMatrix2Matrix(const YHAMG::CSRMatrix& yhMatrix) {
        auto rowPtr = yhMatrix.rowptr;
        auto colind = yhMatrix.colind;
        auto values = yhMatrix.values;
        auto nRows = yhMatrix.size[0];
        auto nCols = yhMatrix.size[1];
        auto nNonZeros = rowPtr[nRows];
        CSRMatrix<int, double, Allocator> myCSRMatrix(nRows, nCols, nNonZeros);
        myCSRMatrix.setRowPtr(rowPtr);
        myCSRMatrix.setColIndex(colind);
        myCSRMatrix.setValues(values);
        return std::move(myCSRMatrix);
    }

    template<typename Integer, typename Real, typename Allocator = MatrixHostAllocator>
    auto Mtx2Matrix(const std::string& fileName) {
        size_t numRows = 0;
        size_t numNonZeros = 0;
        MtxProcessor::readCSRSize(fileName, numRows, numNonZeros);
        CSRMatrix<Integer, Real, Allocator> myCSRMatrix(numRows, numRows, numNonZeros);
        auto* rowPtr = new Integer[numRows+1];
        auto* colind = new Integer[numNonZeros];
        auto* values = new Real[numNonZeros];
        MtxProcessor::readCSR(fileName, rowPtr, colind, values, numRows, numNonZeros);
        myCSRMatrix.setRowPtr(rowPtr);
        myCSRMatrix.setColIndex(colind);
        myCSRMatrix.setValues(values);
        return std::move(myCSRMatrix);
    }

    template<typename Real, typename Allocator = MatrixHostAllocator>
    auto Mtx2Vector(const std::string& fileName) {
        size_t numRows = 0;
        MtxProcessor::readVectorSize(fileName, numRows);
        Vector<Real, Allocator> myVector(numRows);
        Real* values = new Real[numRows];
        MtxProcessor::readVector(fileName, values, numRows);
        myVector.setValues(values);
        return std::move(myVector);
    }
}

#endif //MYAMG_DATACONVERT_CUH